package com.example.teacherservice.service;

import com.example.teacherservice.dto.*;
import com.example.teacherservice.entity.*;
import com.example.teacherservice.repository.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class LearningProgressService {

    private final StuCouProgressRepository progressRepo;
    private final ChapterRepository chapterRepo;
    private final CourseRepository courseRepo;
    private final StuCourseRepository stuCourseRepo;

    @Transactional
    public void updateLearningProgress(ProgressUpdateDTO dto) {
        // 1. 获取或创建学习进度记录
        StuCouProgress progress = progressRepo.findByStuIdAndCouIdAndChaId(
                        dto.getStudentId(), dto.getCourseId(), dto.getChapterId())
                .orElseGet(() -> {
                    StuCouProgress newProgress = new StuCouProgress();
                    newProgress.setStuId(dto.getStudentId());
                    newProgress.setCouId(dto.getCourseId());
                    newProgress.setChaId(dto.getChapterId());
                    return newProgress;
                });

        // 2. 更新关键字段
        if (dto.getTotalDuration() != null) {
            progress.setMediaDuration(dto.getTotalDuration());
        }

        if (dto.getCurrentPosition() != null) {
            progress.setMediaProgress(dto.getCurrentPosition());
        }

        if (dto.getLearnedDuration() != null) {
            progress.setLearnedDuration(dto.getLearnedDuration());
        }

        if (dto.getLearnedStatus() != null) {
            progress.setLearnedStatus(dto.getLearnedStatus());
        }

        // 2. 更新关键字段
        if (dto.getTotalDuration() != null) {
            progress.setMediaDuration(dto.getTotalDuration());
        }

        // 3. 自动计算完成状态
        if (progress.getMediaDuration() != null && progress.getMediaDuration() > 0) {
            if (progress.getMediaProgress() >= progress.getMediaDuration() * 0.95) {
                progress.setLearnedStatus(1);
            }
        }

        progressRepo.save(progress);
    }

    private StuCouProgress createNewProgress(ProgressUpdateDTO dto) {
        StuCouProgress progress = new StuCouProgress();
        progress.setStuId(dto.getStudentId());
        progress.setCouId(dto.getCourseId());
        progress.setChaId(dto.getChapterId());
        progress.setMediaDuration(dto.getTotalDuration());
        progress.setMediaProgress(0L);
        progress.setLearnedDuration(0L);
        progress.setLearnedStatus(0);
        progress.setDeleted(0); // 显式设置deleted为0
        return progress;
    }

    private Long calculateEffectiveDuration(Long lastPosition, Long currentDuration, Long newPosition) {
        if (lastPosition == null) {
            return newPosition; // 第一次记录
        }
        if (newPosition > lastPosition) {
            return currentDuration + (newPosition - lastPosition);
        }
        return currentDuration; // 没有新增时长
    }

    private boolean shouldMarkAsCompleted(StuCouProgress progress, Long currentPosition) {
        if (progress.getMediaDuration() == null || progress.getMediaDuration() == 0) {
            return false;
        }

        // 完成条件：达到95%或最后5秒
        return currentPosition >= progress.getMediaDuration() * 0.95 ||
                currentPosition >= progress.getMediaDuration() - 5;
    }

    private Long calculateEffectiveDuration(StuCouProgress progress, Long newPosition) {
        Long lastPosition = progress.getPositioning() != null ? progress.getPositioning() : 0;
        Long duration = progress.getLearnedDuration() != null ? progress.getLearnedDuration() : 0;

        if (newPosition > lastPosition) {
            duration += (newPosition - lastPosition);
        }

        progress.setPositioning(newPosition);
        return duration;
    }

    public ProgressResponseDTO getChapterProgress(Long studentId, Long courseId, Long chapterId) {
        Optional<StuCouProgress> progressOpt = progressRepo.findByStuIdAndCouIdAndChaId(studentId, courseId, chapterId);
        Optional<Chapter> chapterOpt = chapterRepo.findById(chapterId);

        ProgressResponseDTO response = new ProgressResponseDTO();
        response.setChapterId(chapterId);
        chapterOpt.ifPresent(chapter -> response.setChapterTitle(chapter.getTitle()));

        if (progressOpt.isPresent()) {
            StuCouProgress progress = progressOpt.get();
            response.setMediaProgress(progress.getMediaProgress());
            response.setMediaDuration(progress.getMediaDuration());
            response.setLearnedStatus(progress.getLearnedStatus());
            response.setLearnedDuration(progress.getLearnedDuration());
            response.setProgress(calculateProgressPercentage(progress));
        } else {
            setDefaultProgressResponse(response);
        }

        return response;
    }

    private double calculateProgressPercentage(StuCouProgress progress) {
        if (progress.getMediaDuration() == null || progress.getMediaDuration() == 0) {
            return progress.getLearnedStatus() == 1 ? 1.0 : 0.0;
        }
        double progressValue = (double) progress.getMediaProgress() / progress.getMediaDuration();
        return Math.min(1.0, Math.max(progressValue, progress.getLearnedStatus() == 1 ? 1.0 : 0.0));
    }

    private void setDefaultProgressResponse(ProgressResponseDTO response) {
        response.setMediaProgress(0L);
        response.setMediaDuration(0L);
        response.setLearnedStatus(0);
        response.setLearnedDuration(0L);
        response.setProgress(0.0);
    }

    public CourseProgressDTO getCourseProgress(Long studentId, Long courseId) {
        CourseProgressDTO response = new CourseProgressDTO();
        response.setCourseId(courseId);
        courseRepo.findById(courseId).ifPresent(course -> response.setCourseName(course.getCouName()));

        List<Chapter> chapters = chapterRepo.findByCourseId(courseId);
        if (chapters.isEmpty()) {
            response.setOverallProgress(0.0);
            return response;
        }

        List<ProgressResponseDTO> chapterProgressList = chapters.stream()
                .map(chapter -> getChapterProgress(studentId, courseId, chapter.getId()))
                .collect(Collectors.toList());

        response.setChapterProgressList(chapterProgressList);
        response.setOverallProgress(calculateAverageProgress(chapterProgressList));
        return response;
    }

    private double calculateAverageProgress(List<ProgressResponseDTO> chapterProgressList) {
        return chapterProgressList.stream()
                .mapToDouble(ProgressResponseDTO::getProgress)
                .average()
                .orElse(0.0);
    }

    @Transactional
    public void markChapterAsCompleted(Long studentId, Long courseId, Long chapterId) {
        StuCouProgress progress = progressRepo.findByStuIdAndCouIdAndChaId(studentId, courseId, chapterId)
                .orElseGet(() -> {
                    StuCouProgress newProgress = new StuCouProgress();
                    newProgress.setStuId(studentId);
                    newProgress.setCouId(courseId);
                    newProgress.setChaId(chapterId);
                    return newProgress;
                });

        chapterRepo.findById(chapterId).ifPresent(chapter -> {
            if (progress.getMediaDuration() == null || progress.getMediaDuration() == 0) {
                progress.setMediaDuration(600L);
            }
        });

        progress.setLearnedStatus(1);
        progress.setMediaProgress(progress.getMediaDuration() != null ? progress.getMediaDuration() : 600L);
        progressRepo.save(progress);
    }

    public List<ProgressResponseDTO> getBatchChapterProgress(Long studentId, Long courseId, List<Long> chapterIds) {
        return chapterIds.stream()
                .map(chapterId -> getChapterProgress(studentId, courseId, chapterId))
                .collect(Collectors.toList());
    }

    public StudentAllCoursesProgressDTO getAllCoursesProgress(Long studentId) {
        StudentAllCoursesProgressDTO response = new StudentAllCoursesProgressDTO();
        response.setStudentId(studentId);

        List<Long> courseIds = stuCourseRepo.findCourseIdsByStudentId(studentId);
        if (courseIds.isEmpty()) {
            response.setOverallProgress(0.0);
            return response;
        }

        List<CourseProgressDTO> coursesProgress = courseIds.stream()
                .map(courseId -> getCourseProgress(studentId, courseId))
                .collect(Collectors.toList());

        response.setCoursesProgress(coursesProgress);
        response.setOverallProgress(calculateOverallProgress(coursesProgress));
        return response;
    }

    private double calculateOverallProgress(List<CourseProgressDTO> coursesProgress) {
        return coursesProgress.stream()
                .mapToDouble(CourseProgressDTO::getOverallProgress)
                .average()
                .orElse(0.0);
    }
}